package com.xuqi.MonitorControl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.Log;


public class MonitorControl
{
	static Context mCurContext = null;

	public interface IMonitor<E>
	{
		public void clearListeners();

		public boolean addListener(E object);

		public boolean removeListener(E object);

		public boolean activate(Context c);

		public void deactivate(Context c);
	}

	protected static class Monitor<E> implements IMonitor<E>
	{

		protected ArrayList<E> mListenerList = null;

		@Override
		public boolean activate(Context c)
		{
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean addListener(E object)
		{
			if (object == null)
			{
				return false;
			}

			if (mListenerList == null)
			{
				mListenerList = new ArrayList<E>();
			}

			mListenerList.add(object);
			if (MonitorControl.mCurContext != null)
			{
				this.activate(MonitorControl.mCurContext);
			}
			return true;
		}

		@Override
		public void deactivate(Context c)
		{
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean removeListener(E object)
		{
			if (mListenerList == null)
			{
				return false;
			}
			boolean brt = mListenerList.remove(object);
			if (mListenerList.isEmpty())
			{
				mListenerList = null;
				if (MonitorControl.mCurContext != null)
				{
					this.deactivate(MonitorControl.mCurContext);
				}
			}
			return brt;
		}

		@Override
		public void clearListeners()
		{
			if (mListenerList != null)
				mListenerList.clear();
			mListenerList = null;
		}

	}

	public static class SDMonitor extends Monitor<ISDStateListener>
	{
		private BroadcastReceiver mBR = null;

		@Override
		public boolean activate(Context c)
		{
			if (mBR != null)
				return false;

			mBR = new BroadcastReceiver()
			{

				@Override
				public void onReceive(Context context, Intent intent)
				{
					send2Listener(intent);
				}

			};

			IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT);
			intentFilter.addAction(Intent.ACTION_MEDIA_REMOVED);
			intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
			intentFilter.addDataScheme("file");
			c.registerReceiver(mBR, intentFilter);

			return true;
		}

		@Override
		public void deactivate(Context c)
		{
			if (mBR != null)
				c.unregisterReceiver(mBR);
			mBR = null;
		}

		void send2Listener(Intent intent)
		{
			Log.d("MonitorControl", "SDMonitor state changed");
			if (mListenerList != null && !mListenerList.isEmpty())
			{
				String action = intent.getAction();
				String path = intent.getDataString();
				ISDStateListener listener = null;
				int count = mListenerList.size();
				for (int index = 0; index < count; ++index)
				{
					listener = mListenerList.get(index);
					if (listener != null)
					{
						listener.onStateChanged(action, path);
					}
				}
			}
		}

	}

	public static class NetMonitor extends Monitor<INetStateListener>
	{
		private BroadcastReceiver mBR = null;
		private ConnectivityManager mCm = null;

		@Override
		public boolean activate(Context c)
		{
			if (mBR != null)
				return false;

			mBR = new BroadcastReceiver()
			{

				@Override
				public void onReceive(Context context, Intent intent)
				{
					send2Listener(intent);
				}

			};

			IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
			c.registerReceiver(mBR, intentFilter);

			mCm = (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
			return true;
		}

		@Override
		public void deactivate(Context c)
		{
			if (mBR != null)
				c.unregisterReceiver(mBR);
			mBR = null;
			mCm = null;
		}

		void send2Listener(Intent intent)
		{
			Log.d("MonitorControl", "NetMonitor state changed");
			if (mListenerList != null && !mListenerList.isEmpty())
			{
				if (mCm == null)
				{
					if (MonitorControl.mCurContext != null)
					{
						mCm = (ConnectivityManager) MonitorControl.mCurContext.getSystemService(Context.CONNECTIVITY_SERVICE);
					}
				}
				if (mCm == null)
				{
					Log.e("MonitorControl", "NetMonitor ConnectivityManager is null");
					return;
				}

				// NetworkInfo info =
				// intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
				NetworkInfo info = mCm.getActiveNetworkInfo();
				if (info == null)
				{
					Log.d("MonitorControl", "NetworkInfo is null");
				}
				else
				{
					Log.d("MonitorControl",
							String.format("NetworkInfo type:\t%d isConnected %s isfailOver %s reason %s subtype %s", info.getType(),
									info.isConnected(), info.isFailover(), info.getReason(), info.getSubtypeName()));
				}
				INetStateListener listener = null;
				int count = mListenerList.size();
				for (int index = 0; index < count; ++index)
				{
					listener = mListenerList.get(index);
					if (listener != null)
					{
						listener.onStateChanged(info);
					}
				}
			}
		}

	}

	public static class TeleMonitor extends Monitor<ITeleStateListener>
	{
		private PhoneStateListener mBR = null;

		@Override
		public boolean activate(Context c)
		{
			if (mBR != null)
				return false;
			mBR = new PhoneStateListener()
			{
				@Override
				public void onServiceStateChanged(ServiceState serviceState)
				{
					send2Listener(serviceState);
				}
			};

			TelephonyManager tm = (TelephonyManager) c.getSystemService(Activity.TELEPHONY_SERVICE);
			tm.listen(mBR, PhoneStateListener.LISTEN_SERVICE_STATE);

			return true;
		}

		@Override
		public void deactivate(Context c)
		{
			if (mBR != null)
			{
				TelephonyManager tm = (TelephonyManager) c.getSystemService(Activity.TELEPHONY_SERVICE);
				tm.listen(mBR, PhoneStateListener.LISTEN_NONE);
			}
			mBR = null;
		}

		void send2Listener(ServiceState serviceState)
		{
			Log.d("MonitorControl", "TeleMonitor state changed");
			if (mListenerList != null && !mListenerList.isEmpty())
			{
				ITeleStateListener listener = null;
				int count = mListenerList.size();
				for (int index = 0; index < count; ++index)
				{
					listener = mListenerList.get(index);
					if (listener != null)
					{
						listener.onStateChanged(serviceState);
					}
				}
			}
		}

	}

	public static class DateMonitor extends Monitor<IDateListener>
	{
		private BroadcastReceiver mBR = null;

		@Override
		public boolean activate(Context c)
		{
			if (mBR != null)
				return false;

			mBR = new BroadcastReceiver()
			{

				@Override
				public void onReceive(Context context, Intent intent)
				{
					send2Listener(intent);
				}

			};

			IntentFilter intentFilter = new IntentFilter(Intent.ACTION_DATE_CHANGED);
			intentFilter.addAction(Intent.ACTION_TIME_CHANGED);
			intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
			intentFilter.addAction(Intent.ACTION_TIME_TICK);
			intentFilter.addAction(Intent.ACTION_DATE_CHANGED);
			c.registerReceiver(mBR, intentFilter);
			return true;
		}

		@Override
		public void deactivate(Context c)
		{
			if (mBR != null)
				c.unregisterReceiver(mBR);
			mBR = null;
		}

		void send2Listener(Intent intent)
		{
			Log.d("MonitorControl", "DateMonitor state changed");
			if (mListenerList != null && !mListenerList.isEmpty())
			{
				long timenow = Calendar.getInstance().getTimeInMillis();
				IDateListener listener = null;
				int count = mListenerList.size();
				for (int index = 0; index < count; ++index)
				{
					listener = mListenerList.get(index);
					if (listener != null)
					{
						listener.onStateChanged(timenow);
					}
				}
			}
		}

	}

	public static class BluetoothMonitor extends Monitor<IBluetoothListener>
	{
		private BroadcastReceiver mBR = null;

		@Override
		public boolean activate(Context c)
		{
			if (mBR != null)
				return false;

			mBR = new BroadcastReceiver()
			{

				@Override
				public void onReceive(Context context, Intent intent)
				{
					send2Listener(intent);
				}

			};

			IntentFilter intentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
			intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
			c.registerReceiver(mBR, intentFilter);
			return true;
		}

		@Override
		public void deactivate(Context c)
		{
			if (mBR != null)
				c.unregisterReceiver(mBR);
			mBR = null;
		}

		void send2Listener(Intent intent)
		{
			Log.d("MonitorControl", " BluetoothMonitor state changed");
			if (mListenerList != null && !mListenerList.isEmpty())
			{
				IBluetoothListener listener = null;
				int count = mListenerList.size();
				for (int index = 0; index < count; ++index)
				{
					listener = mListenerList.get(index);
					if (listener != null)
					{
						listener.onStateChanged(intent);
					}
				}
			}
		}

	}

	public static class ExtPowerMonitor extends Monitor<IExtPowerListener>
	{
		private BroadcastReceiver mBR = null;

		@Override
		public boolean activate(Context c)
		{
			if (mBR != null)
				return false;

			mBR = new BroadcastReceiver()
			{

				@Override
				public void onReceive(Context context, Intent intent)
				{
					send2Listener(intent);
				}

			};

			IntentFilter intentFilter = new IntentFilter(Intent.ACTION_POWER_CONNECTED);
			intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
			c.registerReceiver(mBR, intentFilter);

			return true;
		}

		@Override
		public void deactivate(Context c)
		{
			if (mBR != null)
				c.unregisterReceiver(mBR);
			mBR = null;
		}

		void send2Listener(Intent intent)
		{
			String action = intent.getAction();
			Log.d("MonitorControl", "ExtPower state changed\t" + action);
			if (mListenerList != null && !mListenerList.isEmpty())
			{
				boolean bExtPowerConnected = false;
				// only when ACTION_POWER_CONNECTED set bExtPowerConnected as
				// true
				if (action.contentEquals(Intent.ACTION_POWER_CONNECTED))
				{
					bExtPowerConnected = true;
				}
				IExtPowerListener listener = null;
				int count = mListenerList.size();
				for (int index = 0; index < count; ++index)
				{
					listener = mListenerList.get(index);
					if (listener != null)
					{
						listener.onStateChanged(bExtPowerConnected);
					}
				}
			}
		}

	}

	public static class AudioMonitor extends Monitor<IAudioListener>
	{
		private BroadcastReceiver mBR = null;

		@Override
		public boolean activate(Context c)
		{
			if (mBR != null)
				return false;

			mBR = new BroadcastReceiver()
			{

				@Override
				public void onReceive(Context context, Intent intent)
				{
					send2Listener(intent);
				}

			};

			IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
			c.registerReceiver(mBR, intentFilter);

			return true;
		}

		@Override
		public void deactivate(Context c)
		{
			if (mBR != null)
				c.unregisterReceiver(mBR);
			mBR = null;
		}

		void send2Listener(Intent intent)
		{
			String action = intent.getAction();
			if (!AudioManager.ACTION_AUDIO_BECOMING_NOISY.contentEquals(action))
			{
				return;
			}
			Log.d("MonitorControl", "Audio become noisy state changed\t" + action);
			if (mListenerList != null && !mListenerList.isEmpty())
			{
				IAudioListener listener = null;
				int count = mListenerList.size();
				for (int index = 0; index < count; ++index)
				{
					listener = mListenerList.get(index);
					if (listener != null)
					{
						listener.onStateChanged();
					}
				}
			}
		}

	}

	public static class HomeKeyMonitor extends Monitor<IHomeKeyListener>
	{
		private static final int DELAYMILLIS = 500;
		private ActivityManager manager = null;
		private List<RunningTaskInfo> running_info = null;
		private static final String BASE_ACTIVITY_NAME_Navi = "SCR_MapNavigationActivity";
		private static final String BASE_ACTIVITY_NAME_Open = "SCR_OpeningActivity";
		private static final String BASE_ACTIVITY_NAME_Attention = "SCR_Opening_Attention";
		private boolean pressHome = true;
		private Handler handler = new Handler();
		private Runnable listentoHomeKey = new Runnable()
		{

			@Override
			public void run()
			{
				running_info = manager.getRunningTasks(1);
				ComponentName component = running_info.get(0).baseActivity;
				boolean result = isPressHome(component.getClassName());
				if (result != pressHome)
				{
					pressHome = result;
					send2Listener(pressHome);
				}
				handler.postDelayed(listentoHomeKey, DELAYMILLIS);
			}

		};

		private boolean isPressHome(String className)
		{
			boolean retValue = true;
			if (className.indexOf(BASE_ACTIVITY_NAME_Open) != -1)
			{
				retValue = false;
			}
			else if (className.indexOf(BASE_ACTIVITY_NAME_Navi) != -1)
			{
				retValue = false;
			}
			else if (className.indexOf(BASE_ACTIVITY_NAME_Attention) != -1)
			{
				retValue = false;
			}
			return retValue;
		}

		@Override
		public boolean activate(Context c)
		{
			// TODO Auto-generated method stub
			if (manager != null)
			{
				return false;
			}
			manager = (ActivityManager) c.getSystemService(Context.ACTIVITY_SERVICE);
			handler.postDelayed(listentoHomeKey, DELAYMILLIS);
			return true;
		}

		@Override
		public void deactivate(Context c)
		{
			// TODO Auto-generated method stub
			handler.removeCallbacks(listentoHomeKey);
			pressHome = true;
			manager = null;
		}

		void send2Listener(boolean isPressed)
		{
			if (mListenerList != null && !mListenerList.isEmpty())
			{
				IHomeKeyListener listener = null;
				int count = mListenerList.size();
				for (int index = 0; index < count; ++index)
				{
					listener = mListenerList.get(index);
					if (listener != null)
					{
						listener.pressedHomeKey(isPressed);
					}
				}
			}
		}
	}

	public static final int MONITOR_SD = 0;
	public static final int MONITOR_NET = 1;
	public static final int MONITOR_TELE = 2;
	public static final int MONITOR_DATE = 3;
	public static final int MONITOR_AUTHTIME = 4;
	public static final int MONITOR_BLUETOOTH = 5;
	public static final int MONITOR_EXTPOWER = 6;
	public static final int MONITOR_AUDIO = 7;
	public static final int MONITOR_HOMEKEY = 8;

	private static SDMonitor mSDMonitor = null;
	private static NetMonitor mNetMonitor = null;
	private static TeleMonitor mTelMonitor = null;
	private static DateMonitor mDateMonitor = null;
	private static BluetoothMonitor mBTMonitor = null;
	private static ExtPowerMonitor mExtPowerMonitor = null;
	private static AudioMonitor mAudioMonitor = null;
	private static HomeKeyMonitor mHomeKeyMonitor = null;

	public interface ISDStateListener
	{
		public void onStateChanged(String action, String path);
	}

	public interface INetStateListener
	{
		public void onStateChanged(NetworkInfo info);
	}

	public interface ITeleStateListener
	{
		public void onStateChanged(ServiceState state);
	}

	public interface IDateListener
	{
		public void onStateChanged(long timeinmillis);
	}

	public interface IAuthTimeListener
	{
		public void onStateChanged(Context context);
	}

	public interface IBluetoothListener
	{
		// public void onStateChanged();
		public void onStateChanged(Intent intent);
	}

	public interface IExtPowerListener
	{
		public void onStateChanged(boolean bExtPowerConnected);
	}

	public interface IAudioListener
	{
		public void onStateChanged();
	}

	public interface IHomeKeyListener
	{
		public void pressedHomeKey(boolean isPressed);
	}

	@SuppressWarnings("unchecked")
	public static IMonitor getMonitor(int type)
	{
		IMonitor monitor = null;
		switch (type)
		{
		case MONITOR_SD:
		{
			if (mSDMonitor == null)
			{
				mSDMonitor = new SDMonitor();
			}
			monitor = mSDMonitor;
		}
			break;
		case MONITOR_NET:
		{
			if (mNetMonitor == null)
			{
				mNetMonitor = new NetMonitor();
			}
			monitor = mNetMonitor;
		}
			break;
		case MONITOR_TELE:
		{
			if (mTelMonitor == null)
			{
				mTelMonitor = new TeleMonitor();
			}
			monitor = mTelMonitor;
		}
			break;
		case MONITOR_DATE:
		{
			if (mDateMonitor == null)
			{
				mDateMonitor = new DateMonitor();
			}
			monitor = mDateMonitor;
		}
			break;
		case MONITOR_BLUETOOTH:
		{
			if (mBTMonitor == null)
			{
				mBTMonitor = new BluetoothMonitor();
			}
			monitor = mBTMonitor;
		}
			break;
		case MONITOR_EXTPOWER:
		{
			if (mExtPowerMonitor == null)
			{
				mExtPowerMonitor = new ExtPowerMonitor();
			}
			monitor = mExtPowerMonitor;
		}
			break;
		case MONITOR_AUDIO:
		{
			if (mAudioMonitor == null)
			{
				mAudioMonitor = new AudioMonitor();
			}
			monitor = mAudioMonitor;
		}
			break;
		case MONITOR_HOMEKEY:
		{
			if (mHomeKeyMonitor == null)
			{
				mHomeKeyMonitor = new HomeKeyMonitor();
			}
			monitor = mHomeKeyMonitor;
		}
			break;
		default:
			break;
		}

		return monitor;
	}

	public static void clearMonitor(int type)
	{
		switch (type)
		{
		case MONITOR_SD:
		{
			if (mSDMonitor != null)
			{
				mSDMonitor.clearListeners();
				mSDMonitor = null;
			}
		}
			break;
		case MONITOR_NET:
		{
			if (mNetMonitor != null)
			{
				mNetMonitor.clearListeners();
				mNetMonitor = null;
			}
		}
			break;
		case MONITOR_TELE:
		{
			if (mTelMonitor != null)
			{
				mTelMonitor.clearListeners();
				mTelMonitor = null;
			}
		}
			break;
		case MONITOR_DATE:
		{
			if (mDateMonitor != null)
			{
				mDateMonitor.clearListeners();
				mDateMonitor = null;
			}
		}
			break;
		case MONITOR_BLUETOOTH:
		{
			if (mBTMonitor != null)
			{
				mBTMonitor.clearListeners();
				mBTMonitor = null;
			}
		}
			break;
		case MONITOR_EXTPOWER:
		{
			if (mExtPowerMonitor != null)
			{
				mExtPowerMonitor.clearListeners();
				mExtPowerMonitor = null;
			}
		}
			break;
		case MONITOR_AUDIO:
		{
			if (mAudioMonitor != null)
			{
				mAudioMonitor.clearListeners();
				mAudioMonitor = null;
			}
		}
			break;
		case MONITOR_HOMEKEY:
		{
			if (mHomeKeyMonitor != null)
			{
				mHomeKeyMonitor.clearListeners();
				mHomeKeyMonitor = null;
			}
		}
			break;
		default:
			break;
		}
	}

	@SuppressWarnings("unchecked")
	public static void activate(Context context, int type)
	{
		IMonitor monitor = null;
		switch (type)
		{
		case MONITOR_SD:
		{
			if (mSDMonitor != null)
			{
				monitor = mSDMonitor;
			}
		}
			break;
		case MONITOR_NET:
		{
			if (mNetMonitor != null)
			{
				monitor = mNetMonitor;
			}
		}
			break;
		case MONITOR_TELE:
		{
			if (mTelMonitor != null)
			{
				monitor = mTelMonitor;
			}
		}
			break;
		case MONITOR_DATE:
		{
			if (mDateMonitor != null)
			{
				monitor = mDateMonitor;
			}
		}
			break;
		case MONITOR_BLUETOOTH:
		{
			if (mBTMonitor != null)
			{
				monitor = mBTMonitor;
			}
		}
			break;
		case MONITOR_EXTPOWER:
		{
			if (mExtPowerMonitor != null)
			{
				monitor = mExtPowerMonitor;
			}
		}
			break;
		case MONITOR_AUDIO:
		{
			if (mAudioMonitor != null)
			{
				monitor = mAudioMonitor;
			}
		}
			break;
		case MONITOR_HOMEKEY:
		{
			if (mHomeKeyMonitor != null)
			{
				monitor = mHomeKeyMonitor;
			}
		}
			break;
		default:
			break;
		}
		if (monitor != null)
		{
			monitor.activate(context);
		}
	}

	@SuppressWarnings("unchecked")
	public static void deactivate(Context context, int type)
	{
		IMonitor monitor = null;
		switch (type)
		{
		case MONITOR_SD:
		{
			if (mSDMonitor != null)
			{
				monitor = mSDMonitor;
			}
		}
			break;
		case MONITOR_NET:
		{
			if (mNetMonitor != null)
			{
				monitor = mNetMonitor;
			}
		}
			break;
		case MONITOR_TELE:
		{
			if (mTelMonitor != null)
			{
				monitor = mTelMonitor;
			}
		}
			break;
		case MONITOR_DATE:
		{
			if (mDateMonitor != null)
			{
				monitor = mDateMonitor;
			}
		}
			break;
		case MONITOR_BLUETOOTH:
		{
			if (mBTMonitor != null)
			{
				monitor = mBTMonitor;
			}
		}
			break;
		case MONITOR_EXTPOWER:
		{
			if (mExtPowerMonitor != null)
			{
				monitor = mExtPowerMonitor;
			}
		}
			break;
		case MONITOR_AUDIO:
		{
			if (mAudioMonitor != null)
			{
				monitor = mAudioMonitor;
			}
		}
			break;
		case MONITOR_HOMEKEY:
		{
			if (mHomeKeyMonitor != null)
			{
				monitor = mHomeKeyMonitor;
			}
		}
			break;
		default:
			break;
		}
		if (monitor != null)
		{
			monitor.deactivate(context);
		}
	}

	public static void activate(Context context)
	{
		if (context == null || context == mCurContext)
			return;

		if (mCurContext != context)
		{
			deactivate(mCurContext);
		}

		if (mSDMonitor != null)
			mSDMonitor.activate(context);

		if (mNetMonitor != null)
			mNetMonitor.activate(context);

		if (mTelMonitor != null)
			mTelMonitor.activate(context);

		// active by user when needed
		 if (mDateMonitor != null)
		 mDateMonitor.activate(context);

		if (mBTMonitor != null)
			mBTMonitor.activate(context);

		// active by user when needed
		// if(mAuthTimeMonitor != null)
		// mAuthTimeMonitor.activate(context);

		// active by user when needed
		// if(mExtPowerMonitor != null)
		// mExtPowerMonitor.activate(context);

		// active by user when needed
		// if(mAudioMonitor != null)
		// mAudioMonitor.activate(context);

		if (mHomeKeyMonitor != null)
		{
			mHomeKeyMonitor.activate(context);
		}

		mCurContext = context;
	}

	public static void deactivate(Context context)
	{
		if (context == null || context != mCurContext)
			return;

		if (mSDMonitor != null)
			mSDMonitor.deactivate(context);

		if (mNetMonitor != null)
			mNetMonitor.deactivate(context);

		if (mTelMonitor != null)
			mTelMonitor.deactivate(context);

		// deactivate by user
		// if (mDateMonitor != null)
		// mDateMonitor.deactivate(context);

		if (mBTMonitor != null)
			mBTMonitor.deactivate(context);

		// deactivate by user
		// if(mAuthTimeMonitor != null)
		// mAuthTimeMonitor.deactivate(context);

		// deactivate by user
		// if(mExtPowerMonitor != null)
		// mExtPowerMonitor.deactivate(context);

		// deactivate by user
		// if(mAudioMonitor != null)
		// mAudioMonitor.deactivate(context);

		if (mHomeKeyMonitor != null)
			mHomeKeyMonitor.deactivate(context);

		mCurContext = null;
	}
}
